# This file contains the fastlane.tools configuration
# You can find the documentation at https://docs.fastlane.tools
#
# For a list of all available actions, check out
#
#     https://docs.fastlane.tools/actions
#
# For a list of all available plugins, check out
#
#     https://docs.fastlane.tools/plugins/available-plugins
#

# Uncomment the line if you want fastlane to automatically update itself
# update_fastlane

default_platform(:ios)

platform :ios do
  before_all do
    setup_circle_ci
  end

  desc "Setup development environment"
  lane :setup_dev do |options|
    begin
      sh("brew install swiftlint")
    rescue => exception
      UI.error("❌ Please install homebrew and then re-run this lane: /bin/bash -c \"$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/HEAD/install.sh)\"")
      raise exception
    end

    pre_commit_link = "../.git/hooks/pre-commit"
    if File.exist?(pre_commit_link) || File.symlink?(pre_commit_link)
      UI.message("pre-commit script already linked ✅")
    else
      UI.message("Linking pre-commit script 🔗")
      Dir.chdir ".." do
        sh("ln -s -f ../../scripts/pre-commit.sh .git/hooks/pre-commit")
      end
    end
  end

  desc "Runs all the tests"
  lane :test do
    scan
    snapshot
  end

  desc "Increment build number"
  lane :bump do |options|
    new_version_number = options[:version]
    fail ArgumentError, "missing version" unless new_version_number
    previous_version_number = current_version_number
    
    version_number_without_prerelease_modifiers = new_version_number.split("-")[0]
    increment_version_number(version_number: version_number_without_prerelease_modifiers)
    
    files_to_update = [
      '../PurchasesCoreSwift.podspec',
      '../Purchases.podspec',
      '../Purchases/Misc/RCSystemInfo.m',
      '../.jazzy.yaml',
      '../.version',
      '../Examples/MagicWeather/MagicWeather.xcodeproj/project.pbxproj',
      '../Examples/MagicWeatherSwiftUI/Magic Weather SwiftUI.xcodeproj/project.pbxproj',
    ]
    for file_to_update in files_to_update
      increment_build_number(previous_version_number, new_version_number, file_to_update)
    end
  end

  desc "Increment build number and update changelog"
  lane :bump_and_update_changelog do |options|
    bump(options)
    attach_changelog_to_master(options[:version])
  end

  desc "Make github release"
  lane :github_release do |options|
    release_version = options[:version]
    fail ArgumentError, "missing version" unless release_version

    begin
      changelog = File.read("../CHANGELOG.latest.md")
    rescue
      fail "please add a CHANGELOG.latest.md file before calling this lane"
    end
    commit_hash = last_git_commit[:commit_hash]
    puts commit_hash

    set_github_release(
      repository_name: "revenuecat/purchases-ios",
      api_token: ENV["GITHUB_TOKEN"],
      name: release_version,
      tag_name: "#{release_version}",
      description: changelog,
      commitish: commit_hash,
      upload_assets: ["Purchases.framework.zip", "Purchases.xcframework.zip"],
      is_draft: false
  )
  end

  desc "Create sandbox account"
  lane :create_sandbox_account do |options|
    email = options[:email]
    fail ArgumentError, "missing email" unless email

    password = options[:password]
    fail ArgumentError, "missing password" unless password
    require 'Spaceship'

    Spaceship::Tunes.login()
    
    Spaceship::Tunes::SandboxTester.create!(email: email, password: password)
  end

  desc "Deployment checks"
  lane :deployment_checks do |options|
    version_number = current_version_number
    check_no_git_tag_exists(version_number)
    check_pods
    carthage_archive
    export_xcframework
    check_no_github_release_exists(version_number)
  end

  desc "Run the carthage archive steps to prepare for carthage distribution"
  lane :carthage_archive do |options|
    carthage_archive
  end

  desc "archive"
  lane :archive do
    match(type: "appstore")
    gym(export_method: "app-store")
  end

  desc "replace API KEY for integration tests"
  lane :replace_api_key_integration_tests do
    replace_in("REVENUECAT_API_KEY", ENV["REVENUECAT_API_KEY"], '../StoreKitTests/Constants.swift')
    replace_in("REVENUECAT_API_KEY", ENV["REVENUECAT_API_KEY"], '../IntegrationTests/CommonFiles/RCIntegrationRunner.m')

    replace_in("REVENUECAT_PROXY_URL", ENV["REVENUECAT_PROXY_URL"].to_s, '../StoreKitTests/Constants.swift', allow_empty: true)
    replace_in("REVENUECAT_PROXY_URL", ENV["REVENUECAT_PROXY_URL"].to_s, '../IntegrationTests/CommonFiles/RCIntegrationRunner.m', allow_empty: true)
  end

  desc "Deploy"
  lane :deploy do |options|
    version_number = current_version_number
    push_pods
    carthage_archive
    export_xcframework
    github_release(version: version_number)
  end

  desc "Prepare next version"
  lane :prepare_next_version do |options|
    old_version_number = current_version_number
    major, minor, _ = old_version_number.split('.')
    next_version = "#{major}.#{minor.to_i + 1}.0"
    next_version_snapshot = "#{next_version}-SNAPSHOT"

    branch_name = "bump/#{next_version_snapshot}"
    sh("git", "checkout", "-b", branch_name)

    bump(version: next_version_snapshot)

    sh("git", "commit", "-am", "Preparing for next version")
    push_to_git_remote

    create_pull_request(
      repo: "revenuecat/purchases-ios",
      title: "Prepare next version: #{next_version_snapshot}",
      base: "main",
      api_token: ENV["GITHUB_TOKEN"],
      head: branch_name
    )
  end

  desc "Export XCFramework"
  lane :export_xcframework do |options|
    output_directory = 'build/xcframeworks'
    platforms = [
        'iOS',
        'macOS',
        'maccatalyst',
        'tvOS',
        'watchOS'
      ]

    create_xcframework(
      destinations: platforms,
      scheme: 'Purchases',
      xcframework_output_directory: output_directory,
      # bitcode produces issues with Catalyst when validating builds, 
      # with a message: "object not signed at all".
      enable_bitcode: false
    )
    # sh runs from the Fastfile's location, but other commands run from the project root.
    output_directory_for_sh = "../#{output_directory}"

    xcframeworks_zip_path_for_sh = "../Purchases.xcframework.zip"
    sh("ditto", "-c", "-k", "--sequesterRsrc", "--keepParent", 
      output_directory_for_sh, 
      xcframeworks_zip_path_for_sh)

  end

  desc "Run StoreKitTests"
  lane :storekit_tests do |options|
    replace_api_key_integration_tests
    scan(scheme: "StoreKitTests", derived_data_path: "scan_derived_data")
  end

  desc "Update swift package commit"
  lane :update_swift_package_commit do
    project_file_locations = [
      '../IntegrationTests/SPMIntegration/SPMIntegration.xcodeproj/project.pbxproj',
      '../Examples/MagicWeather/MagicWeather.xcodeproj/project.pbxproj',
      '../Examples/MagicWeatherSwiftUI/Magic Weather SwiftUI.xcodeproj/project.pbxproj',
    ]

    old_kind_line = "kind = branch;"
    new_kind_line = "kind = revision;"

    commit_hash = last_git_commit[:commit_hash]
    old_branch_line = "branch = main;"
    new_revision_line = "revision = #{commit_hash};"

    project_file_locations.each { |project_file_location|
      replace_in(old_kind_line, new_kind_line, project_file_location)
      replace_in(old_branch_line, new_revision_line, project_file_location)
    }
  end

end

def push_pods
  pod_push(path: "PurchasesCoreSwift.podspec")
  pod_push(path: "Purchases.podspec", synchronous: true)
end

def check_no_git_tag_exists(version_number)
  if git_tag_exists(tag: version_number, remote: true, remote_name: 'origin')
    raise "git tag with version #{version_number} already exists!"
  end
end


def check_no_github_release_exists(version_number)
  found_release_number = get_github_release(url: "revenuecat/purchases-ios", version: version_number)
  raise "Release with version #{version_number} already exists!" unless found_release_number.nil?
end

def carthage_archive
  Dir.chdir("..") do
    # As of Carthage 0.38.0, we still can't archive xcframeworks directly. 
    # there are also some issues which prevent us from archiving frameworks directly, since
    # carthage can't deal with architectures for simulators and for Apple Silicon correctly.
    # We use this script as a workaround until this is fixed. 
    # https://github.com/Carthage/Carthage/releases/0.38.0
    sh("./scripts/carthage.sh", "build", "--no-skip-current")
    sh("./scripts/carthage.sh", "archive", "Purchases")
  end
end

def check_pods
  pod_lib_lint(verbose: true, podspec:'PurchasesCoreSwift.podspec')
  pod_lib_lint(verbose: true, podspec:'Purchases.podspec', include_podspecs:'PurchasesCoreSwift.podspec')
end

def increment_build_number(previous_version_number, new_version_number, file_path)
  replace_in(previous_version_number, new_version_number, file_path)
end

def attach_changelog_to_master(version_number)
  current_changelog = File.open("../CHANGELOG.latest.md", 'r')
  master_changelog = File.open("../CHANGELOG.md", 'r')

  current_changelog_data = current_changelog.read
  master_changelog_data = master_changelog.read

  current_changelog.close  
  master_changelog.close

  File.open("../CHANGELOG.md", 'w') { |master_changelog_write_mode|
    version_header = "## #{version_number}"
    whole_file_data = "#{version_header}\n#{current_changelog_data}\n#{master_changelog_data}"
    puts "going to save. Contents - #{whole_file_data}"
    
    master_changelog_write_mode.write(whole_file_data)
  }
end

def replace_in(previous_text, new_text, path, allow_empty=false)
  if new_text.to_s.strip.empty? and not allow_empty
    fail "Missing `new_text` in call to `replace_in`, looking for replacement for #{previous_text} 😵."
  end
  sed_regex = 's|' + previous_text + '|' + new_text + '|'
  backup_extension = '.bck'
  sh("sed", '-i', backup_extension, sed_regex, path)
end

def current_version_number
  File.read("../.version")
end